package com.wuqing.utils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.wuqing.bean.MethodInvokeRecord;
import org.apache.commons.collections4.CollectionUtils;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;

/**
 * @author wuqing
 * @date 2020/8/8
 */
public class TpMonitorHelper {

    /**
     * key serviceName+methodName
     */
    private static ConcurrentMap<String, List<MethodInvokeRecord>> recordMap = Maps.newConcurrentMap();

    /**
     * 并发锁
     */
    private static Lock writeLock = new ReentrantReadWriteLock().writeLock();

    public static void addRecord(MethodInvokeRecord record) {
        String key = MethodInvokeRecord.genKey(record);
        writeLock.lock();
        try {
            if (recordMap.containsKey(key)) {
                recordMap.get(key).add(record);
            } else {
                recordMap.put(key, Lists.newArrayList(record));
            }
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 每个方法都进行统计
     *
     * @param percent
     * @return
     */
    public static Map<String, MethodInvokeRecord> getPt(double percent) {
        long current = System.currentTimeMillis();
        writeLock.lock();

        try {
            HashMap<String, MethodInvokeRecord> result = Maps.newHashMap();
            if (recordMap == null || recordMap.size() == 0) {
                return result;
            }
            for (Map.Entry<String, List<MethodInvokeRecord>> entry : recordMap.entrySet()) {
                //遍历和处理每一个方法
                List<MethodInvokeRecord> recordList = entry.getValue();

                if (CollectionUtils.isEmpty(recordList)) {
                    result.put(entry.getKey(), null);
                } else {
                    //处理最近一分钟的记录
                    List<MethodInvokeRecord> validRecords = recordList.stream().filter(it -> current - it.getRecordTime() <= 60 * 1000)
                            .sorted(Comparator.comparing(MethodInvokeRecord::getCost))
                            .collect(Collectors.toList());
                    //只保留有效记录就行了
                    System.out.println("统计Tp结果，过期的数据做一下去除处理。methodName=" + entry.getKey());
                    recordMap.put(entry.getKey(), validRecords);
                    if (CollectionUtils.isEmpty(validRecords)) {
                        result.put(entry.getKey(), null);
                    } else {
                        int totalReqSize = validRecords.size();
                        double tpNo = Math.ceil(totalReqSize * percent);
                        if (tpNo == 0) {
                            tpNo = 1;
                        }
                        MethodInvokeRecord record = validRecords.get((int) (tpNo - 1));
                        result.put(entry.getKey(), record);
                    }
                }
            }

            return result;
        } finally {
            writeLock.unlock();
        }
    }

}